package com.yst.suivi.services.user;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;

import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.FinderException;
import javax.ejb.RemoveException;
import javax.ejb.SessionBean;
import javax.naming.NamingException;

import org.apache.commons.lang.StringUtils;

import com.yst.suivi.comparator.NameObjectComparator;
import com.yst.suivi.data.project.Project;
import com.yst.suivi.data.user.User;
import com.yst.suivi.data.user.UserLocalHome;
import com.yst.suivi.data.user.UserUtil;
import com.yst.suivi.data.user.authentication.Principal;
import com.yst.suivi.data.user.authentication.PrincipalLocalHome;
import com.yst.suivi.data.user.authentication.PrincipalUtil;
import com.yst.suivi.data.user.authentication.RoleLocalHome;
import com.yst.suivi.data.user.authentication.RoleUtil;
import com.yst.suivi.services.AbstractSessionBean;
import com.yst.suivi.services.assignation.AssignationViewUtil;
import com.yst.suivi.services.exceptions.BusinessErrorCode;
import com.yst.suivi.services.exceptions.BusinessException;

/**
 * @ejb.bean display-name="UserService" jndi-name="UserHomeRemote"
 *           name="UserView" type="Stateless" view-type="both"
 */
public class UserServiceBean extends AbstractSessionBean implements SessionBean
{
	/**
	 * @throws CreateException
	 * @ejb.create-method view-type = "both"
	 */
	public void ejbCreate() throws CreateException
	{
		// by default nothing to do
	}

	/**
	 * This method create a new user.
	 * 
	 * @param standard
	 * @return standard updated
	 * @throws CreateException
	 * @ejb.interface-method view-type = "both"
	 * @ejb.transaction type = "Required"
	 */
	public String createUser(String login, String nom, String prenom, String societe, String code, String mail, Float tjm) throws NamingException, CreateException
	{
		checkConstraints(login, nom, prenom, societe, code, mail);
		User usr;
		UserLocalHome home = UserUtil.getLocalHome();
		usr = home.create();
		updateObject(nom, prenom, usr, societe, code, mail, tjm, null);
		usr.setLogin(login);
		PrincipalLocalHome prHome = PrincipalUtil.getLocalHome();
		prHome.create(login, "suivi");
		RoleLocalHome roleHome = RoleUtil.getLocalHome();
		roleHome.create(login);
		return usr.getId();
	}

	/**
	 * La methode remplie l'objet EJB avec les valeurs fournies
	 * 
	 * @param nom
	 * @param prenom
	 * @param usr
	 */
	private void updateObject(String nom, String prenom, User usr, String societe, String code, String mail, Float tjm, Calendar dteFin)
	{
		usr.setNom(nom);
		usr.setPrenom(prenom);
		usr.setSociete(societe);
		usr.setCode(code);
		usr.setMail(mail);
		usr.setTjm(tjm);
		usr.setEndDate(dteFin);
	}

	/**
	 * The method checks if all the business constraints are verified.
	 * 
	 * @param login
	 * @param nom
	 * @param prenom
	 */
	private void checkConstraints(String login, String nom, String prenom, String societe, String code, String mail)
	{
		String[] parameter =
		{ "user", "login" };
		checkEmptyField(login, parameter);
		checkFieldLength(login, SIMPlE_FIELD_MAX_LENGTH, "login");
		checkUnicity(login, "usr", "principalid", "-1");
		checkConstraints(nom, prenom, societe, code, mail);
	}

	/**
	 * The method checks all the constraints for the field nom and prenom of the
	 * user.
	 * 
	 * @param nom
	 * @param prenom
	 */
	private void checkConstraints(String nom, String prenom, String societe, String code, String mail)
	{
		checkFieldLength(nom, SIMPlE_FIELD_MAX_LENGTH, "nom");
		checkFieldLength(prenom, SIMPlE_FIELD_MAX_LENGTH, "prenom");
		checkFieldLength(societe, SIMPlE_FIELD_MAX_LENGTH, "societe");
		checkFieldLength(code, SIMPlE_FIELD_MAX_LENGTH, "code");
		checkFieldLength(mail, SIMPlE_FIELD_MAX_LENGTH, "mail");
		if (null != mail)
		{
			if (!mail.matches("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}$"))
			{
				throw new BusinessException(BusinessErrorCode.WRONG_MAIL_FORMAT, new String[0]);
			}
		}
	}

	/**
	 * This method list all the user of the system.
	 * 
	 * @param standard
	 * @ejb.interface-method view-type = "both"
	 */

	public Collection findAllUser() throws NamingException, FinderException
	{
		ArrayList retour = new ArrayList(UserUtil.getLocalHome().findAll());
		Collections.sort(retour, NameObjectComparator.comparator);
		return retour;
	}

	/**
	 * This method list all the user of the system.
	 * 
	 * @param standard
	 * @ejb.interface-method view-type = "both"
	 */

	public Collection findAllUserActive() throws NamingException, FinderException
	{
		ArrayList retour = new ArrayList(UserUtil.getLocalHome().findAllActive(new Long(Calendar.getInstance().getTimeInMillis())));
		Collections.sort(retour, NameObjectComparator.comparator);
		return retour;
	}

	/**
	 * This method update a user.
	 * 
	 * @param standard
	 * @return standard updated
	 * @throws NamingException
	 * @throws FinderException
	 * @ejb.interface-method view-type = "both"
	 * @ejb.transaction type = "Required"
	 */
	public void storeUser(String id, String nom, String prenom, String societe, String code, String mail, Float tjm, Calendar dteFin) throws FinderException, NamingException
	{
		checkConstraints(nom, prenom, societe, code, mail);
		UserLocalHome home = UserUtil.getLocalHome();
		User usr = home.findByPrimaryKey(id);
		updateObject(nom, prenom, usr, societe, code, mail, tjm, dteFin);
	}

	/**
	 * This method delete an user.
	 * 
	 * @param standard
	 * @throws NamingException
	 * @throws RemoveException
	 * @throws EJBException
	 * @throws FinderException
	 * @throws FinderException
	 * @throws SQLException
	 * @throws CreateException
	 * @ejb.interface-method view-type = "both"
	 * @ejb.transaction type = "Required"
	 */
	public void deleteUser(String id) throws NamingException, EJBException, RemoveException, FinderException, CreateException, SQLException
	{
		UserLocalHome home = UserUtil.getLocalHome();
		User usr = home.findByPrimaryKey(id);
		Collection lstPrj = AssignationViewUtil.getLocalHome().create().getProjectFor(usr);
		if (lstPrj.isEmpty())
		{
			PrincipalLocalHome prHome = PrincipalUtil.getLocalHome();
			prHome.remove(usr.getLogin());
			RoleLocalHome roleHome = RoleUtil.getLocalHome();
			roleHome.remove(usr.getLogin());

			home.remove(id);
		}
		else
		{
			boolean first = true;
			String[] params = new String[1];
			StringBuffer buf = new StringBuffer();
			for (Iterator it = lstPrj.iterator(); it.hasNext();)
			{
				if (first)
				{
					first = false;
				}
				else
				{
					buf.append(", ");
				}
				buf.append(((Project) it.next()).getNom());
			}
			params[0] = buf.toString();
			String[] data = new String[0];
			throw new BusinessException(BusinessErrorCode.DELETED_USER_ASSIGN_TO_PROJECT, data, params);
		}
	}

	/**
	 * @ejb.interface-method view-type = "both"
	 * @param login
	 * @return
	 * @throws FinderException
	 * @throws NamingException
	 */
	public User findByLogin(String login) throws FinderException, NamingException
	{
		return UserUtil.getLocalHome().findByLogin(login);
	}

	/**
	 * @ejb.interface-method view-type = "both"
	 * @param key
	 * @return
	 * @throws FinderException
	 * @throws NamingException
	 */
	public User findByKey(String key) throws FinderException, NamingException
	{
		return UserUtil.getLocalHome().findByPrimaryKey(key);
	}

	/**
	 * @ejb.interface-method view-type = "both"
	 * @ejb.transaction type="Required"
	 * @param oldPwd
	 * @param newPwd
	 * @param confirmationPwd
	 * @throws NamingException
	 * @throws FinderException
	 */
	public void changePwd(String oldPwd, String newPwd, String confirmationPwd) throws NamingException, FinderException
	{
		PrincipalLocalHome home = PrincipalUtil.getLocalHome();
		// check if user can change the password
		Principal principal = home.findByPrimaryKey(getContext().getCallerPrincipal().getName());
		if (principal.getPwd().equals(oldPwd))
		{
			// check if the password contains only alpha numerical characters
			if (newPwd.matches("[A-Za-z0-9]*") && !StringUtils.isEmpty(newPwd))
			{
				// check if the password is confirmed
				if (newPwd.equals(confirmationPwd))
				{
					principal.setPwd(newPwd);
				}
				else
				{
					String[] parameters =
					{};
					throw new BusinessException(BusinessErrorCode.WRONG_PASSWORD, parameters);
				}
			}
			else
			{
				String[] parameters =
				{ "pwd" };
				throw new BusinessException(BusinessErrorCode.WRONG_CHARACTERS, parameters);
			}
		}
		else
		{
			String[] parameters =
			{};
			throw new BusinessException(BusinessErrorCode.WRONG_OLD_PASSWORD, parameters);
		}
	}
}
